/**
 * 
 */
package mybatisplus.conf;

import static org.mybatis.generator.internal.util.StringUtility.isTrue;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import org.mybatis.generator.api.CommentGenerator;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.CompilationUnit;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.InnerClass;
import org.mybatis.generator.api.dom.java.InnerEnum;
import org.mybatis.generator.api.dom.java.JavaElement;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.config.MergeConstants;
import org.mybatis.generator.config.PropertyRegistry;

/**
 * @author qijy
 *
 */
public class MyCommentGenerator implements CommentGenerator {
	private Properties properties;
	private Properties systemPro;
	private boolean suppressDate;
	private boolean suppressAllComments;
	private boolean isSwagger;
	private boolean isMongo;
	private boolean isJpa;
	private String currentDateStr;

	public MyCommentGenerator() {
		super();
		properties = new Properties();
		systemPro = System.getProperties();
		suppressDate = false;
		suppressAllComments = false;
		isSwagger = false;
		isMongo = false;
		isJpa = false;
		currentDateStr = (new SimpleDateFormat("yyy年MM月dd日")).format(new Date());
	}

	/**
	 * 
	 */
	public void addJavaFileComment(CompilationUnit compilationUnit) {
		if (!suppressAllComments) {
			compilationUnit.addFileCommentLine("/**");
			compilationUnit.addFileCommentLine(" * Title: " + compilationUnit.getType().getShortName() + ".java");
			if (!isBlank(properties.getProperty("systemName")))
				compilationUnit.addFileCommentLine(" * Description: " + compilationUnit.getType().getShortName()
						+ " for " + properties.getProperty("systemName") + " System");
			compilationUnit.addFileCommentLine(" * Copyright: Copyright (c) " + getDateString().substring(0, 4));
			compilationUnit.addFileCommentLine(" * Company: sany");
			compilationUnit.addFileCommentLine(
					" * @author " + systemPro.getProperty("user.name") + " " + getDateString() + "");
			compilationUnit.addFileCommentLine(" */");
		}

		Set<FullyQualifiedJavaType> importedTypeSet = new HashSet<FullyQualifiedJavaType>();
		if (!(compilationUnit.getType().getShortName().endsWith("Example")
				|| compilationUnit.getType().getShortName().endsWith("Mapper"))) {
			if (isSwagger) {
				importedTypeSet.add(new FullyQualifiedJavaType("io.swagger.annotations.ApiModelProperty"));
				importedTypeSet.add(new FullyQualifiedJavaType("io.swagger.annotations.ApiModel"));
			}
			if (isMongo) {
				importedTypeSet.add(new FullyQualifiedJavaType("org.springframework.data.mongodb.core.mapping.Field"));
				importedTypeSet.add(new FullyQualifiedJavaType("javax.persistence.Id"));
				importedTypeSet
						.add(new FullyQualifiedJavaType("org.springframework.data.mongodb.core.mapping.Document"));
			}

			if (isJpa) {
				importedTypeSet.add(new FullyQualifiedJavaType("javax.persistence.Id"));
				importedTypeSet.add(new FullyQualifiedJavaType("javax.persistence.Column"));
				importedTypeSet.add(new FullyQualifiedJavaType("javax.persistence.Entity"));
				importedTypeSet.add(new FullyQualifiedJavaType("javax.persistence.GeneratedValue"));
				importedTypeSet.add(new FullyQualifiedJavaType("javax.persistence.GenerationType"));
				importedTypeSet.add(new FullyQualifiedJavaType("javax.persistence.Table"));
			}
		}
		if (importedTypeSet != null && importedTypeSet.size() > 0)
			compilationUnit.addImportedTypes(importedTypeSet);

	}

	/**
	 * Adds a suitable comment to warn users that the element was generated, and
	 * when it was generated.
	 */
	public void addComment(XmlElement xmlElement) {
		return;
	}

	public void addRootComment(XmlElement rootElement) {
		// add no document level comments by default
		return;
	}

	public void addConfigurationProperties(Properties properties) {
		this.properties.putAll(properties);
		suppressDate = isTrue(properties.getProperty(PropertyRegistry.COMMENT_GENERATOR_SUPPRESS_DATE));
		suppressAllComments = isTrue(properties.getProperty(PropertyRegistry.COMMENT_GENERATOR_SUPPRESS_ALL_COMMENTS));
		isMongo = isTrue(properties.getProperty("isMongo"));
		isSwagger = isTrue(properties.getProperty("isSwagger"));
		isJpa = isTrue(properties.getProperty("isJpa"));
	}

	/**
	 * This method adds the custom javadoc tag for. You may do nothing if you do not
	 * wish to include the Javadoc tag - however, if you do not include the Javadoc
	 * tag then the Java merge capability of the eclipse plugin will break.
	 * 
	 * @param javaElement the java element
	 */
	protected void addJavadocTag(JavaElement javaElement, boolean markAsDoNotDelete) {
		javaElement.addJavaDocLine(" *");
		StringBuilder sb = new StringBuilder();
		sb.append(" * ");
		sb.append(MergeConstants.NEW_ELEMENT_TAG);
		if (markAsDoNotDelete) {
			sb.append(" do_not_delete_during_merge");
		}
		String s = getDateString();
		if (s != null) {
			sb.append(' ');
			sb.append(s);
		}
		javaElement.addJavaDocLine(sb.toString());
	}

	/**
	 * This method returns a formated date string to include in the Javadoc tag and
	 * XML comments. You may return null if you do not want the date in these
	 * documentation elements.
	 * 
	 * @return a string representing the current timestamp, or null
	 */
	protected String getDateString() {
		String result = null;
		if (!suppressDate) {
			result = currentDateStr;
		}
		return result;
	}

	/**
	 * 
	 * <p>
	 * Title: �ж��ַ����Ƿ�Ϊ��
	 * </p>
	 * 
	 * @author Jonny Qi 2019��9��11�� ����9:37:44
	 * @param str ��Ҫ�ж����ַ���
	 * @return boolean true Ϊ�� false ��Ϊ��
	 */
	protected static boolean isBlank(String str) {
		int strLen;

		if (str == "null" || str == null || (strLen = str.length()) == 0) {
			return true;
		}
		for (int i = 0; i < strLen; i++) {
			if ((Character.isWhitespace(str.charAt(i)) == false)) {
				return false;
			}
		}
		return true;
	}

	public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable) {
		if (suppressAllComments) {
			return;
		}
		StringBuilder sb = new StringBuilder();
		innerClass.addJavaDocLine("/**");
		sb.append(" * ");
		sb.append(introspectedTable.getFullyQualifiedTable());
		sb.append(" ");
		sb.append(getDateString());
		innerClass.addJavaDocLine(sb.toString().replace("\n", " "));
		innerClass.addJavaDocLine(" */");
	}

	public void addEnumComment(InnerEnum innerEnum, IntrospectedTable introspectedTable) {
		if (!suppressAllComments) {
			StringBuilder sb = new StringBuilder();
			innerEnum.addJavaDocLine("/**");
			sb.append(" * ");
			sb.append(introspectedTable.getFullyQualifiedTable());
			innerEnum.addJavaDocLine(sb.toString().replace("\n", " "));
			innerEnum.addJavaDocLine(" */");
		}
	}

	public void addFieldComment(Field field, IntrospectedTable introspectedTable,
			IntrospectedColumn introspectedColumn) {
		if (!suppressAllComments) {
			if (!isBlank(introspectedColumn.getRemarks()))
				field.addJavaDocLine("//" + introspectedColumn.getRemarks());

			if (isSwagger) {
				String swaggerIgnoreFields = introspectedTable.getTableConfigurationProperty("swaggerIgnoreFields");
				System.out.println("field.getName()-->"+field.getName());
				if (!isBlank(introspectedColumn.getRemarks())) {
					if (isBlank(introspectedColumn.getDefaultValue())) {
						if (!isBlank(swaggerIgnoreFields)
								&& (swaggerIgnoreFields.contains(introspectedColumn.getActualColumnName())
										|| swaggerIgnoreFields.contains(field.getName()))) {
							field.addAnnotation("@ApiModelProperty(name = \"" + field.getName() + "\", value = \""
									+ introspectedColumn.getRemarks() + "\", dataType = \""
									+ field.getType().getShortName() + "\", notes =  \""
									+ introspectedColumn.getRemarks() + "\", hidden = true )");
						} else {
							field.addAnnotation("@ApiModelProperty(name = \"" + field.getName() + "\", value = \""
									+ introspectedColumn.getRemarks() + "\", dataType = \""
									+ field.getType().getShortName() + "\", notes = \""
									+ introspectedColumn.getRemarks() + "\")");
						}
					} else {
						if (!isBlank(swaggerIgnoreFields)
								&& (swaggerIgnoreFields.contains(introspectedColumn.getActualColumnName())
										|| swaggerIgnoreFields.contains(field.getName()))) {

							String fieldStr = "@ApiModelProperty(name = \"" + field.getName() + "\", value = \""
									+ introspectedColumn.getRemarks() + "\" , dataType = \""
									+ field.getType().getShortName() + "\"";

							if (!"CURRENT_TIMESTAMP".equals(introspectedColumn.getDefaultValue()))
								fieldStr += ", example = \"" + introspectedColumn.getDefaultValue() + "\"";

							fieldStr += ", notes = \"" + introspectedColumn.getRemarks() + "\", hidden = true)";

							field.addAnnotation(fieldStr);
						} else {
							String fieldStr = "@ApiModelProperty(name = \"" + field.getName() + "\", value = \""
									+ introspectedColumn.getRemarks() + "\" , dataType = \""
									+ field.getType().getShortName() + "\"";

							if (!"CURRENT_TIMESTAMP".equals(introspectedColumn.getDefaultValue()))
								fieldStr += ", example = \"" + introspectedColumn.getDefaultValue() + "\"";

							fieldStr += ", notes = \"" + introspectedColumn.getRemarks() + "\")";

							field.addAnnotation(fieldStr);
						}

					}
				}
			}

			List<IntrospectedColumn> primaryKeyColumns = introspectedTable.getPrimaryKeyColumns();
			IntrospectedColumn primaryKey = null;
			if (primaryKeyColumns != null && primaryKeyColumns.size() > 0) {
				primaryKey = primaryKeyColumns.get(0);
			}

			if (isMongo) {
				if (introspectedColumn.isIdentity()
						|| (primaryKey.getActualColumnName().equals(introspectedColumn.getActualColumnName()))) {
					field.addAnnotation("@Id");
				} else {
					field.addAnnotation("@Field(\"" + introspectedColumn.getActualColumnName() + "\")");
				}
			}

			if (isJpa) {

				if (introspectedColumn.isIdentity()
						|| (primaryKey.getActualColumnName().equals(introspectedColumn.getActualColumnName()))) {// 主键
					field.addAnnotation("@Id");

					if (introspectedColumn.isAutoIncrement() || primaryKey.isAutoIncrement())
						field.addAnnotation("@GeneratedValue(strategy = GenerationType.IDENTITY)");
				} else {
					int jdbcType = introspectedColumn.getJdbcType();
					String columnStr = "@Column(name = \"" + introspectedColumn.getActualColumnName()
							+ "\" , columnDefinition =\"";

					String jdbcTypeName = "";
					if ("INTEGER".equals(introspectedColumn.getJdbcTypeName()))
						jdbcTypeName = "int";
					else
						jdbcTypeName = introspectedColumn.getJdbcTypeName().toLowerCase();

					if (jdbcType == -1)
						jdbcTypeName = "text ";
					else if (jdbcType == -4)
						jdbcTypeName = "blob ";

					columnStr += jdbcTypeName;

					if (!(jdbcType == 93 || jdbcType == 92 || jdbcType == 91 || jdbcType == -1 || jdbcType == -4)) { // TIMESTAMP+time+date+
																														// (text/lobgtext)+(longblob/blob/mediumblob)
						if (jdbcType == 7 || jdbcType == 8 || jdbcType == 3) {// double float decimal
							columnStr += "(" + introspectedColumn.getLength() + "," + introspectedColumn.getScale()
									+ ")";
						} else {
							columnStr += "(" + introspectedColumn.getLength() + ")";
						}
					}

					if (!introspectedColumn.isNullable()) {
						columnStr += " NOT NULL  ";
					} else {
						columnStr += " NULL ";
					}

					if (!(jdbcType == -1 || jdbcType == -4)) {
						if (jdbcType == 93 || jdbcType == 92 || jdbcType == 91) // TIMESTAMP time date
							columnStr += introspectedColumn.getDefaultValue() == null
									? (!introspectedColumn.isNullable() ? "DEFAULT ''" : "DEFAULT NULL")
									: "DEFAULT " + introspectedColumn.getDefaultValue();
						else
							columnStr += introspectedColumn.getDefaultValue() == null
									? (!introspectedColumn.isNullable() ? "DEFAULT ''" : "DEFAULT NULL")
									: "DEFAULT " + "'" + introspectedColumn.getDefaultValue() + "'";
					}

					columnStr += " COMMENT '" + introspectedColumn.getRemarks() + "'\")";
					field.addAnnotation(columnStr);
				}
			}
		}

	}

	public void addFieldComment(Field field, IntrospectedTable introspectedTable) {
		if (!suppressAllComments) {
			StringBuilder sb = new StringBuilder();
			field.addJavaDocLine("/**");
			sb.append(" * ");
			sb.append(introspectedTable.getFullyQualifiedTable());
			field.addJavaDocLine(sb.toString().replace("\n", " "));
			field.addJavaDocLine(" */");
		}

	}

	public void addGeneralMethodComment(Method method, IntrospectedTable introspectedTable) {
		if (!suppressAllComments) {
			method.addJavaDocLine("/**");
			addJavadocTag(method, false);
			method.addJavaDocLine(" */");
		}
	}

	public void addGetterComment(Method method, IntrospectedTable introspectedTable,
			IntrospectedColumn introspectedColumn) {
		if (!suppressAllComments) {
			method.addJavaDocLine("/**");
			StringBuilder sb = new StringBuilder();
			sb.append(introspectedColumn.getRemarks());
			sb.setLength(0);
			sb.append(" * @return ");
			sb.append(introspectedColumn.getActualColumnName());
			sb.append(" ");
			sb.append(introspectedColumn.getRemarks());
			method.addJavaDocLine(sb.toString().replace("\n", " "));
			method.addJavaDocLine(" */");
		}

	}

	public void addSetterComment(Method method, IntrospectedTable introspectedTable,
			IntrospectedColumn introspectedColumn) {
		if (!suppressAllComments) {
			method.addJavaDocLine("/**");
			StringBuilder sb = new StringBuilder();
			sb.append(introspectedColumn.getRemarks());
			Parameter parm = method.getParameters().get(0);
			sb.setLength(0);
			sb.append(" * @param ");
			sb.append(parm.getName());
			sb.append(" ");
//			sb.append("the "+parm.getName() +"to set");
			sb.append(introspectedColumn.getRemarks());
			method.addJavaDocLine(sb.toString().replace("\n", " "));
			method.addJavaDocLine(" */");
		}

	}

	public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable, boolean markAsDoNotDelete) {
		if (!suppressAllComments) {
			StringBuilder sb = new StringBuilder();
			innerClass.addJavaDocLine("/**");
			sb.append(" * ");
			sb.append(introspectedTable.getFullyQualifiedTable());
			innerClass.addJavaDocLine(sb.toString().replace("\n", " "));
			sb.setLength(0);
			sb.append(" * @author ");
			sb.append(systemPro.getProperty("user.name"));
			sb.append(" ");
			sb.append(currentDateStr);
			innerClass.addJavaDocLine(" */");
		}

	}

	/*
	 * @author Jonny Qi
	 *
	 * @time 2019��8��30��
	 * 
	 * @see
	 * org.mybatis.generator.api.CommentGenerator#addModelClassComment(org.mybatis.
	 * generator.api.dom.java.TopLevelClass,
	 * org.mybatis.generator.api.IntrospectedTable)
	 */

	public void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
		// ��ȡ��ע��
		String remarks = introspectedTable.getRemarks(),
//				swaggerClassRemark = introspectedTable.getTableConfigurationProperty("swaggerClassRemark"),
				tableName = introspectedTable.getTableConfiguration().getTableName();
		topLevelClass.addJavaDocLine("/**");
		topLevelClass.addJavaDocLine(" *  @author " + systemPro.get("user.name"));
		topLevelClass.addJavaDocLine(" *  @time " + getDateString());
		topLevelClass.addJavaDocLine(" *  @since " + tableName);
		if (!isBlank(remarks))
			topLevelClass.addJavaDocLine(" *  @Description " + remarks);
		topLevelClass.addJavaDocLine(" */");
		if (isSwagger)
			topLevelClass.addAnnotation("@ApiModel(value=\"" + remarks + "\",description=\"" + remarks + "\")");

		if (isMongo)
			topLevelClass.addAnnotation("@Document(collection = \"" + tableName + "\")");

		if (isJpa) {
			topLevelClass.addAnnotation("@Entity");
			topLevelClass.addAnnotation("@Table(name = \"" + tableName + "\")");
			topLevelClass.addAnnotation("@org.hibernate.annotations.Table(appliesTo = \"" + tableName
					+ "\", comment = \"" + remarks + "\")");
		}

	}

	/*
	 * @author Jonny Qi
	 *
	 * @time 2019��8��30��
	 * 
	 * @see
	 * org.mybatis.generator.api.CommentGenerator#addGeneralMethodAnnotation(org.
	 * mybatis.generator.api.dom.java.Method,
	 * org.mybatis.generator.api.IntrospectedTable, java.util.Set)
	 */

	public void addGeneralMethodAnnotation(Method method, IntrospectedTable introspectedTable,
			Set<FullyQualifiedJavaType> imports) {

	}

	/*
	 * @author Jonny Qi
	 *
	 * @time 2019��8��30��
	 * 
	 * @see
	 * org.mybatis.generator.api.CommentGenerator#addGeneralMethodAnnotation(org.
	 * mybatis.generator.api.dom.java.Method,
	 * org.mybatis.generator.api.IntrospectedTable,
	 * org.mybatis.generator.api.IntrospectedColumn, java.util.Set)
	 */

	public void addGeneralMethodAnnotation(Method method, IntrospectedTable introspectedTable,
			IntrospectedColumn introspectedColumn, Set<FullyQualifiedJavaType> imports) {

	}

	/*
	 * @author Jonny Qi
	 *
	 * @time 2019��8��30��
	 * 
	 * @see
	 * org.mybatis.generator.api.CommentGenerator#addFieldAnnotation(org.mybatis.
	 * generator.api.dom.java.Field, org.mybatis.generator.api.IntrospectedTable,
	 * java.util.Set)
	 */

	public void addFieldAnnotation(Field field, IntrospectedTable introspectedTable,
			Set<FullyQualifiedJavaType> imports) {

	}

	/*
	 * @author Jonny Qi
	 *
	 * @time 2019��8��30��
	 * 
	 * @see
	 * org.mybatis.generator.api.CommentGenerator#addFieldAnnotation(org.mybatis.
	 * generator.api.dom.java.Field, org.mybatis.generator.api.IntrospectedTable,
	 * org.mybatis.generator.api.IntrospectedColumn, java.util.Set)
	 */

	public void addFieldAnnotation(Field field, IntrospectedTable introspectedTable,
			IntrospectedColumn introspectedColumn, Set<FullyQualifiedJavaType> imports) {

	}

	/*
	 * @author Jonny Qi
	 *
	 * @time 2019��8��30��
	 * 
	 * @see
	 * org.mybatis.generator.api.CommentGenerator#addClassAnnotation(org.mybatis.
	 * generator.api.dom.java.InnerClass,
	 * org.mybatis.generator.api.IntrospectedTable, java.util.Set)
	 */

	public void addClassAnnotation(InnerClass innerClass, IntrospectedTable introspectedTable,
			Set<FullyQualifiedJavaType> imports) {

	}
}
